package com.idlewow.game.hub.message.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.idlewow.character.service.CharacterService;
import com.idlewow.common.model.CommonResult;
import com.idlewow.game.GameWorld;
import com.idlewow.character.model.Character;
import com.idlewow.game.hub.message.dto.WowMessage;
import com.idlewow.game.hub.message.dto.WowMessageCode;
import com.idlewow.game.hub.message.dto.WowMessageHeader;
import com.idlewow.game.hub.message.dto.request.ChatRequest;
import com.idlewow.game.hub.message.dto.request.LoadCacheRequest;
import com.idlewow.game.hub.message.dto.request.LoginRequest;
import com.idlewow.game.hub.message.dto.request.MoveRequest;
import com.idlewow.game.hub.message.dto.request.RefreshOnlineRequest;
import com.idlewow.game.hub.message.dto.response.ChatResponse;
import com.idlewow.game.hub.message.dto.response.LoadCacheResponse;
import com.idlewow.game.hub.message.dto.response.LoginResponse;
import com.idlewow.game.hub.message.dto.response.MoveResponse;
import com.idlewow.game.hub.message.dto.response.RefreshOnlineResponse;
import com.idlewow.game.hub.message.vo.MapInfo;
import com.idlewow.game.hub.message.vo.OnlineInfo;
import com.idlewow.map.model.MapCoord;
import com.idlewow.map.model.WowMap;
import com.idlewow.map.service.MapCoordService;
import com.idlewow.map.service.WowMapService;
import com.idlewow.mob.model.MapMob;
import com.idlewow.mob.service.MapMobService;
import com.idlewow.support.util.CacheUtil;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.Session;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class MessageHandler {
    private static final Logger logger = LogManager.getLogger(MessageHandler.class);

    @Autowired
    CharacterService characterService;
    @Autowired
    WowMapService wowMapService;
    @Autowired
    MapMobService mapMobService;
    @Autowired
    MapCoordService mapCoordService;

    /**
     * 消息处理
     *
     * @param session session
     * @param message 消息
     */
    public void handleMessage(Session session, String message) {
        WowMessage<?> wowMessage = JSONObject.parseObject(message, WowMessage.class);
        WowMessageHeader header = wowMessage.getHeader();
        String messageCode = header.getMessageCode();
        switch (messageCode) {
            case WowMessageCode.LoadCache:
                this.handleLoadCacheMessage(session, (WowMessage<LoadCacheRequest>) wowMessage);
                break;
            case WowMessageCode.RefreshOnline:
                this.handleRefreshOnlineMessage(session, (WowMessage<RefreshOnlineRequest>) wowMessage);
                break;
            case WowMessageCode.Login:
                this.handleLoginMessage(session, (WowMessage<LoginRequest>) wowMessage);
                break;
            case WowMessageCode.Chat:
                this.handleChatMessage(session, (WowMessage<ChatRequest>) wowMessage);
                break;
            case WowMessageCode.Move:
                this.handleMoveMessage(session, (WowMessage<MoveRequest>) wowMessage);
                break;
            default:
                break;
        }
    }

    /**
     * 给指定客户端发送消息
     *
     * @param session 客户端session
     * @param message 消息内容
     */
    private void sendOne(Session session, String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        }
    }

    /**
     * 给所有客户端发送消息
     *
     * @param message 消息内容
     */
    private void sendAll(String message) {
        try {
            for (Session session : GameWorld.OnlineSession) {
                session.getBasicRemote().sendText(message);
            }
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        }
    }

    /**
     * 登陆加载
     *
     * @param session session
     * @param message 消息
     */
    private void handleLoginMessage(Session session, WowMessage<LoginRequest> message) {
        WowMessageHeader header = message.getHeader();
        header.setResponseTime(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        LoginResponse response = new LoginResponse();
        Character character = GameWorld.OnlineCharacter.get(session.getId());
        String mapId = character.getMapId();
        MapInfo mapInfo = this.loadMapInfo(mapId);
        response.setMapInfo(mapInfo);
        OnlineInfo onlineInfo = this.loadOnlineInfo(mapId);
        response.setOnlineInfo(onlineInfo);
        WowMessage wowMessage = new WowMessage<>(header, response);
        this.sendOne(session, JSON.toJSONString(wowMessage));
    }

    /**
     * 发送聊天
     *
     * @param session session
     * @param message 消息
     */
    private void handleChatMessage(Session session, WowMessage<ChatRequest> message) {
        WowMessageHeader header = message.getHeader();
        header.setResponseTime(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        ChatRequest request = message.getContent();
        ChatResponse response = new ChatResponse();
        response.setSendId(request.getSendId());
        response.setSendName(request.getSendName());
        response.setRecvId(request.getRecvId());
        response.setRecvName(request.getRecvName());
        response.setMessage(request.getMessage());
        response.setChannel(request.getChannel());
        WowMessage wowMessage = new WowMessage<>(header, response);
        if (request.getChannel().equals(GameWorld.ChatChannel.WORLD)) {
            this.sendAll(JSON.toJSONString(wowMessage));
        } else if (request.getChannel().equals(GameWorld.ChatChannel.PRIVATE)) {
            // todo 发送消息给指定玩家
        } else if (request.getChannel().equals(GameWorld.ChatChannel.LOCAL)) {
            // todo 发送消息给当前地图玩家
        }
    }

    /**
     * 加载缓存
     *
     * @param session session
     * @param message 消息
     */
    private void handleLoadCacheMessage(Session session, WowMessage<LoadCacheRequest> message) {
        WowMessageHeader header = message.getHeader();
        header.setResponseTime(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        LoadCacheResponse response = new LoadCacheResponse();
        Map<String, Integer> levelExpMap = new HashMap<>();
        for (Integer key : CacheUtil.levelExpMap.keySet()) {
            levelExpMap.put(key.toString(), CacheUtil.levelExpMap.get(key));
        }

        response.setLevelExpMap(levelExpMap);
        WowMessage wowMessage = new WowMessage<>(header, response);
        this.sendOne(session, JSON.toJSONString(wowMessage));
    }

    /**
     * 地图移动
     *
     * @param session session
     * @param message 消息
     */
    private void handleMoveMessage(Session session, WowMessage<MoveRequest> message) {
        WowMessageHeader header = message.getHeader();
        header.setResponseTime(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        MoveRequest request = message.getContent();
        Character character = GameWorld.OnlineCharacter.get(session.getId());
        String fromMapId = character.getMapId();
        String destMapId = request.getDestMapId();
        GameWorld.MapCharacter.get(fromMapId).remove(character);
        GameWorld.MapCharacter.get(destMapId).add(character);
        character.setMapId(destMapId);
        MapInfo mapInfo = this.loadMapInfo(destMapId);
        OnlineInfo onlineInfo = this.loadOnlineInfo(destMapId);
        MoveResponse response = new MoveResponse();
        response.setMapInfo(mapInfo);
        response.setOnlineInfo(onlineInfo);
        WowMessage wowMessage = new WowMessage<>(header, response);
        this.sendOne(session, JSON.toJSONString(wowMessage));
    }

    /**
     * 刷新在线列表
     *
     * @param session session
     * @param message 消息
     */
    private void handleRefreshOnlineMessage(Session session, WowMessage<RefreshOnlineRequest> message) {
        WowMessageHeader header = message.getHeader();
        header.setResponseTime(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        Character character = GameWorld.OnlineCharacter.get(session.getId());
        String mapId = character.getMapId();
        OnlineInfo onlineInfo = this.loadOnlineInfo(mapId);
        RefreshOnlineResponse response = new RefreshOnlineResponse();
        response.setOnlineInfo(onlineInfo);
        WowMessage wowMessage = new WowMessage<>(header, response);
        this.sendOne(session, JSON.toJSONString(wowMessage));
    }

    /**
     * 读取地图信息
     *
     * @param mapId 地图ID
     * @return
     */
    private MapInfo loadMapInfo(String mapId) {
        MapInfo mapInfo = new MapInfo();
        CommonResult commonResult = wowMapService.find(mapId);
        if (commonResult.isSuccess()) {
            WowMap wowMap = (WowMap) commonResult.getData();
            mapInfo.setWowMap(wowMap);
        }

        List<MapCoord> mapCoordList = mapCoordService.listByFromMapId(mapId);
        mapInfo.setMapCoordList(mapCoordList);

        return mapInfo;
    }

    /**
     * 读取在线列表
     *
     * @param mapId 地图ID
     * @return
     */
    private OnlineInfo loadOnlineInfo(String mapId) {
        OnlineInfo onlineInfo = new OnlineInfo();
        List<MapMob> mapMobList = mapMobService.listByMapId(mapId);
        onlineInfo.setMapMobList(mapMobList);
        List<Character> mapCharacterList = GameWorld.MapCharacter.get(mapId);
        onlineInfo.setMapCharacterList(mapCharacterList);
        return onlineInfo;
    }
}
